package com.xiaomaoguai.fcp.pre.kepler.sftp.utils;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

/**
 * @author WeiHui
 * @version v1.0.0
 * @date 2019/4/17 21:13
 * @since JDK 1.8
 */
public class Sftp {

	private static final Logger logger = LoggerFactory.getLogger(Sftp.class);
	private Session session;
	private ChannelSftp channel;
	private String host;
	private int port;
	private int timeout;
	private String username;
	private String password;

	public Sftp(String host, int port, String username, String password) {
		this(host, port, 0, username, password);
	}

	public Sftp(String host, int port, int timeout, String username, String password) {
		this.session = null;
		this.channel = null;
		this.timeout = 0;
		this.host = host;
		this.port = port;
		this.timeout = timeout;
		this.username = username;
		this.password = password;
		logger.info("init sftp for {}@{}", username, host);
	}

	public boolean login() {
		try {
			JSch jsch = new JSch();
			this.session = jsch.getSession(this.username, this.host, this.port);
			if (this.password != null) {
				this.session.setPassword(this.password);
			}

			Properties config = new Properties();
			config.put("StrictHostKeyChecking", "no");
			this.session.setConfig(config);
			this.session.setTimeout(this.timeout);
			this.session.connect();
			logger.info("session connected");
			logger.debug("opening channel");
			this.channel = (ChannelSftp)this.session.openChannel("sftp");
			this.channel.connect();
			logger.info("channel connected");
			return true;
		} catch (JSchException var3) {
			logger.error("sftp login failed", var3);
			return false;
		}
	}

	public boolean uploadFile(String pathName, String fileName, InputStream input) {
		String currentDir = this.currentDir();
		if (!this.changeDir(pathName)) {
			return false;
		} else {
			boolean var6;
			try {
				this.channel.put(input, fileName, 0);
				boolean var5;
				if (this.existFile(fileName)) {
					logger.info("upload success, fileName: {}", fileName);
					var5 = true;
					return var5;
				}

				logger.error("upload failed, fileName: {}", fileName);
				var5 = false;
				return var5;
			} catch (SftpException var10) {
				logger.error("upload failed", var10);
				var6 = false;
			} finally {
				this.changeDir(currentDir);
			}

			return var6;
		}
	}

	public boolean uploadFile(String pathName, String fileName, String localFile) {
		String currentDir = this.currentDir();
		if (!this.changeDir(pathName)) {
			return false;
		} else {
			boolean var6;
			try {
				File file = new File(localFile);
				if (file.exists() && fileName == null) {
					fileName = file.getName();
				}

				this.channel.put(localFile, fileName, new Sftp.FileProgressMonitor(), 0);
				if (this.existFile(fileName)) {
					logger.info("upload success, fileName: {}", fileName);
					var6 = true;
					return var6;
				}

				logger.error("upload failed, fileName: {}", fileName);
				var6 = false;
			} catch (SftpException var10) {
				logger.error("upload failed", var10);
				var6 = false;
				return var6;
			} finally {
				this.changeDir(currentDir);
			}

			return var6;
		}
	}

	public boolean downloadFile(String remotePath, String fileName, String localPath) {
		String currentDir = this.currentDir();
		if (!this.changeDir(remotePath)) {
			return false;
		} else {
			File dir = new File(localPath);
			if (!dir.exists() && !dir.mkdirs()) {
				logger.error("localPath={} is not exist,can't mkdir");
			}

			boolean var8;
			try {
				String localFilePath = localPath + File.separator + fileName;
				this.channel.get(fileName, localFilePath, new Sftp.FileProgressMonitor());
				File localFile = new File(localFilePath);
				if (localFile.exists()) {
					logger.info("download success, fileName: {}", fileName);
					var8 = true;
					return var8;
				}

				logger.error("download file failed, fileName: {}", fileName);
				var8 = false;
			} catch (SftpException var12) {
				logger.error("download file failed", var12);
				boolean var7 = false;
				return var7;
			} finally {
				this.changeDir(currentDir);
			}

			return var8;
		}
	}

	public boolean changeDir(String pathName) {
		if (pathName != null && !pathName.trim().equals("")) {
			try {
				this.channel.cd(pathName.replaceAll("\\\\", "/"));
				logger.debug("directory success changed, current dir={}", this.channel.pwd());
				return true;
			} catch (SftpException var3) {
				logger.error("failed to change directory", var3);
				return false;
			}
		} else {
			logger.error("invalid pathName {}", pathName);
			return false;
		}
	}

	public boolean changeToParentDir() {
		return this.changeDir("..");
	}

	public boolean changeToHomeDir() {
		String homeDir;
		try {
			homeDir = this.channel.getHome();
		} catch (SftpException var3) {
			logger.error("can not get home directory", var3);
			return false;
		}

		return this.changeDir(homeDir);
	}

	public boolean makeDir(String dirName) {
		try {
			this.channel.mkdir(dirName);
			logger.info("directory success created, dir=" + dirName);
			return true;
		} catch (SftpException var3) {
			logger.error("failed to create directory", var3);
			return false;
		}
	}

	public boolean makeDirs(String dirName) {
		String currentDir = this.currentDir();

		boolean var4;
		try {
			String[] folders = dirName.split(System.getProperty("file.separator"));
			if (ArrayUtils.isNotEmpty(folders)) {
				String[] var15 = folders;
				int var5 = folders.length;

				for(int var6 = 0; var6 < var5; ++var6) {
					String folder = var15[var6];
					if (!StringUtils.isBlank(folder)) {
						boolean result = this.existDir(folder);
						if (result) {
							this.channel.cd(folder);
						} else {
							result = this.makeDir(folder);
							if (!result) {
								boolean var9 = false;
								return var9;
							}

							this.channel.cd(folder);
						}
					}
				}
			}

			logger.info("directory success created, dir=" + dirName);
			var4 = true;
			return var4;
		} catch (SftpException var13) {
			logger.error("failed to create directory", var13);
			var4 = false;
		} finally {
			this.changeDir(currentDir);
		}

		return var4;
	}

	public boolean delDir(String dirName) {
		if (!this.changeDir(dirName)) {
			return false;
		} else {
			Vector list;
			try {
				list = this.channel.ls(this.channel.pwd());
			} catch (SftpException var7) {
				logger.error("can not list directory", var7);
				return false;
			}

			Iterator var3 = list.iterator();

			while(var3.hasNext()) {
				ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry)var3.next();
				String fileName = entry.getFilename();
				if (!".".equals(fileName) && !"..".equals(fileName)) {
					if (entry.getAttrs().isDir()) {
						this.delDir(fileName);
					} else {
						this.delFile(fileName);
					}
				}
			}

			if (!this.changeToParentDir()) {
				return false;
			} else {
				try {
					this.channel.rmdir(dirName);
					logger.info("directory " + dirName + " success deleted");
					return true;
				} catch (SftpException var6) {
					logger.error("failed to delete directory " + dirName, var6);
					return false;
				}
			}
		}
	}

	public boolean delFile(String fileName) {
		if (fileName != null && !fileName.trim().equals("")) {
			try {
				this.channel.rm(fileName);
				logger.debug("file " + fileName + " success deleted");
				return true;
			} catch (SftpException var3) {
				logger.error("failed to delete file " + fileName, var3);
				return false;
			}
		} else {
			logger.error("invalid filename");
			return false;
		}
	}

	public String[] ls() {
		return this.list(Sftp.Filter.ALL);
	}

	public String[] ls(String pathName) {
		String currentDir = this.currentDir();
		if (!this.changeDir(pathName)) {
			return new String[0];
		} else {
			String[] result = this.list(Sftp.Filter.ALL);
			return !this.changeDir(currentDir) ? new String[0] : result;
		}
	}

	public String[] lsFiles() {
		return this.list(Sftp.Filter.FILE);
	}

	public String[] lsFiles(String pathName) {
		String currentDir = this.currentDir();
		if (!this.changeDir(pathName)) {
			return new String[0];
		} else {
			String[] result = this.list(Sftp.Filter.FILE);
			return !this.changeDir(currentDir) ? new String[0] : result;
		}
	}

	public String[] lsDirs() {
		return this.list(Sftp.Filter.DIR);
	}

	public String[] lsDirs(String pathName) {
		String currentDir = this.currentDir();
		if (!this.changeDir(pathName)) {
			return new String[0];
		} else {
			String[] result = this.list(Sftp.Filter.DIR);
			return !this.changeDir(currentDir) ? new String[0] : result;
		}
	}

	public boolean exist(String name) {
		return this.exist(this.ls(), name);
	}

	public boolean exist(String path, String name) {
		return this.exist(this.ls(path), name);
	}

	public boolean existFile(String name) {
		return this.exist(this.lsFiles(), name);
	}

	public boolean existFile(String path, String name) {
		return this.exist(this.lsFiles(path), name);
	}

	public boolean existDir(String name) {
		return this.exist(this.lsDirs(), name);
	}

	public boolean existDir(String path, String name) {
		return this.exist(this.lsDirs(path), name);
	}

	public String currentDir() {
		try {
			return this.channel.pwd();
		} catch (SftpException var2) {
			logger.error("failed to get current dir", var2);
			return this.homeDir();
		}
	}

	public void logout() {
		if (this.channel != null) {
			this.channel.quit();
			this.channel.disconnect();
		}

		if (this.session != null) {
			this.session.disconnect();
		}

		logger.info("logout success");
	}

	private String[] list(Sftp.Filter filter) {
		Vector list;
		try {
			list = this.channel.ls(this.channel.pwd());
		} catch (SftpException var6) {
			logger.error("can not list directory", var6);
			return new String[0];
		}

		List<String> resultList = new ArrayList();
		Iterator var4 = list.iterator();

		while(var4.hasNext()) {
			ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry)var4.next();
			if (this.filter(entry, filter)) {
				resultList.add(entry.getFilename());
			}
		}

		return (String[])resultList.toArray(new String[0]);
	}

	private boolean filter(ChannelSftp.LsEntry entry, Sftp.Filter f) {
		if (f.equals(Sftp.Filter.ALL)) {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..");
		} else if (f.equals(Sftp.Filter.FILE)) {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..") && !entry.getAttrs().isDir();
		} else if (!f.equals(Sftp.Filter.DIR)) {
			return false;
		} else {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..") && entry.getAttrs().isDir();
		}
	}

	private String homeDir() {
		try {
			return this.channel.getHome();
		} catch (SftpException var2) {
			return "/";
		}
	}

	private boolean exist(String[] strArr, String str) {
		if (strArr != null && strArr.length != 0) {
			if (str != null && !str.trim().equals("")) {
				String[] var3 = strArr;
				int var4 = strArr.length;

				for(int var5 = 0; var5 < var4; ++var5) {
					String s = var3[var5];
					if (s.equalsIgnoreCase(str)) {
						return true;
					}
				}

				return false;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	private class FileProgressMonitor implements SftpProgressMonitor {
		private long start;

		private FileProgressMonitor() {
		}

		public void init(int op, String src, String dest, long max) {
			this.start = System.currentTimeMillis();
			if (op == 0) {
				Sftp.logger.info("PUT [" + src + "] to [" + dest + "] size=" + max / 1024L + "KB");
			}

			if (op == 1) {
				Sftp.logger.info("GET [" + src + "] in [" + dest + "] size=" + max / 1024L + "KB");
			}

		}

		public boolean count(long count) {
			return true;
		}

		public void end() {
			Sftp.logger.info("success, cost: " + (System.currentTimeMillis() - this.start) + "ms");
		}
	}

	private static enum Filter {
		ALL,
		FILE,
		DIR;

		private Filter() {
		}
	}

}
